using System.Diagnostics;
using System.IO.Ports;
using System.Management;
using System.Text;

namespace NtripConfig
{
    public partial class MainForm : Form
    {
        #region 成员变量
        /// <summary>
        /// 串口通讯接口
        /// </summary>
        private SerialPort? _serialPort;
        private bool _connected = false;
        private readonly List<string> _portNames = [];
        private readonly List<string> _PortDesc = [];
        #endregion

        public MainForm()
        {
            InitializeComponent();
            // 枚举串口列表
            GetSerialPortInfo();
            int preferIndex = 0;
            for (var i = 0; i < _portNames.Count; i++)
            {
                mCbxComs.Items.Add($"{_portNames[i]} [ {_PortDesc[i]} ]");
                if (_PortDesc[i].Contains("Quectel USB REPL"))
                {
                    preferIndex = i;
                }
            }

            if (mCbxComs.Items.Count > 0)
            {
                mCbxComs.SelectedIndex = preferIndex;
            }

            mLabReq.Text = " ";
            mLabSys.Text = " ";
            mLabRsp.Text = " ";
            statusLabel4.Text = " ";

            // 增加版本号显示
            //var idx = Application.ProductVersion.IndexOf("+");
            //Text += $" v{Application.ProductVersion[..idx]}";
            Text += " v1.1.0";
        }

        private void GetSerialPortInfo()
        {
            //调用 WMI，获取 Win32_PnPEntity，即所有设备
            using var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_PnPEntity");
            var hardInfos = searcher.Get();
            foreach (var hardInfo in hardInfos)
            {
                var nm = hardInfo.Properties["Name"].Value?.ToString();
                if (nm?.Contains("(COM") == true)
                {
                    var idx = nm.IndexOf("(COM");
                    Trace.WriteLine(nm);
                    var desc = nm[..idx]; //截取描述（名称）
                    var name = nm.Substring(idx + 1, nm.Length - idx - 2); //截取串口号
                    var manu = hardInfo.Properties["Manufacturer"].Value.ToString(); //获取制造商
                    Trace.WriteLine($"{desc}|{name}|{manu}");

                    _portNames.Add(name);
                    _PortDesc.Add(desc);
                }
            }
            searcher.Dispose();
        }

        private void SendCmdReq(string strReq)
        {
            _serialPort?.WriteLine(strReq);
            mLabReq.Text = strReq;
            Thread.Sleep(100);
        }

        private void mBtnRead_Click(object sender, EventArgs e)
        {
            if (!_connected)
            {
                MessageBox.Show("请打开串口");
                return;
            }

            mEdtUsr.Text = string.Empty;
            mEdtPwd.Text = string.Empty;
            mEdtSrvAddr.Text = string.Empty;
            mEdtSrvPort.Text = string.Empty;
            mEdtMountPoint.Text = string.Empty;
            Update();

            if (_serialPort == null)
            {
                MessageBox.Show("无效串口");
                return;
            }

            SendCmdReq("AT+USR=?");
            SendCmdReq("AT+PWD=?");
            SendCmdReq("AT+SRV=?");
            SendCmdReq("AT+PORT=?");
            SendCmdReq("AT+MOUNTPOINT=?");            
            SendCmdReq("AT+IMEI=?");
            SendCmdReq("AT+ICCID=?");
        }

        private void mBtnWrite_Click(object sender, EventArgs e)
        {
            if (!_connected || null == _serialPort)
            {
                MessageBox.Show("请打开串口");
                return;
            }

            SendCmdReq($"AT+USR={StrProc(mEdtUsr.Text)}");
            SendCmdReq($"AT+PWD={StrProc(mEdtPwd.Text)}");
            SendCmdReq($"AT+SRV={StrProc(mEdtSrvAddr.Text)}");
            SendCmdReq($"AT+PORT={StrProc(mEdtSrvPort.Text)}");
            SendCmdReq($"AT+MOUNTPOINT={StrProc(mEdtMountPoint.Text)}");
        }

        private void mBtnOpen_Click(object sender, EventArgs e)
        {
            if (null == mCbxComs.SelectedItem)
            {
                return;
            }

            if (_connected)
            {
                _serialPort?.Close();
                mCbxComs.Enabled = true;
                mBtnOpen.Text = "打开";
                return;
            }

            // 打开通讯端口
            _serialPort = new SerialPort
            {
                PortName = _portNames[mCbxComs.SelectedIndex],
                BaudRate = 115200,
                DataBits = 8,
                StopBits = StopBits.One
            };

            try
            {
                _serialPort.Open();
                _serialPort.DataReceived += OnDataReceived;
                mCbxComs.Enabled = !_serialPort.IsOpen;
                mBtnOpen.Text = "关闭";
                _connected = true;
            }
            catch (Exception)
            {
                mCbxComs.Enabled = true;
                mBtnOpen.Text = "打开";
                _connected = false;
            }
        }

        /// <summary>
        /// 将Hex数据转换成字符串，例如 0xae00cf => "AE00CF"
        /// </summary>
        public static string HexStr(byte[] bytes)
        {
            if (bytes == null || bytes.Length == 0)
                return string.Empty;
            var strB = new StringBuilder();
            foreach (var t in bytes)
                strB.Append(t.ToString("X2"));
            return strB.ToString();
        }

        private static string[] StrProc(string txt)
        {
            var ret = txt.Trim();
            return ret.Split("\r\n", StringSplitOptions.RemoveEmptyEntries);
        }

        private void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            // 接收到串口数据，进行解析处理
            try
            {
                while (_serialPort?.BytesToRead > 0)
                {
                    var rcvData = new byte[_serialPort.BytesToRead];
                    _serialPort.Read(rcvData, 0, rcvData.Length);
                    var strRsp = Encoding.Default.GetString(rcvData);
                    BeginInvoke(new Action(() => { mLabRsp.Text = strRsp.Trim(); }));
                    Trace.WriteLine($"RCV: {strRsp}");
                    foreach (var s in StrProc(strRsp))
                    {                        
                        RspDataProcess(s);
                    }                    
                }
            }
            catch (Exception)
            {
                // ignored
            }
        }

        static private string GetLTEState2Str(uint state)
        {
            if (0 == state) return "正常";
            if (1 == state) return "无SIM卡";
            if (2 == state) return "无移动网络";
            if (3 == state) return "等待卫星定位";
            if (4 == state) return "服务器连接失败";
            if (5 == state) return "服务器未授权";
            if (6 == state) return "RTCM数据超时";
            if (7 == state) return "重启中";

            return "未知";
        }

        static private string GetCSQLevelStr(uint csq)
        {
            if (csq <= 9)  return "信号差";
            if (csq <= 14) return "信号一般";
            if (csq <= 19) return "信号好";
            if (csq <= 31) return "信号很好";
            
            return "无信号";
        }

        private void RspDataProcess(string strRsp)
        {            
            var idx = strRsp.IndexOf('=');
            if (strRsp.Contains("USR") && idx > 0)
            {
                BeginInvoke(new Action(() => { mEdtUsr.Text = strRsp[(idx + 1)..].Trim(); }));
            }
            if (strRsp.Contains("PWD") && idx > 0)
            {
                BeginInvoke(new Action(() => { mEdtPwd.Text = strRsp[(idx + 1)..]; }));
            }
            if (strRsp.Contains("SRV") && idx > 0)
            {
                BeginInvoke(new Action(() => { mEdtSrvAddr.Text = strRsp[(idx + 1)..]; }));
            }
            if (strRsp.Contains("PORT") && idx > 0)
            {
                BeginInvoke(new Action(() => { mEdtSrvPort.Text = strRsp[(idx + 1)..]; }));
            }
            if (strRsp.Contains("MOUNTPOINT") && idx > 0)
            {
                BeginInvoke(new Action(() => { mEdtMountPoint.Text = strRsp[(idx + 1)..]; }));
            }
            if (strRsp.Contains("ICCID") && idx > 0)
            {
                BeginInvoke(new Action(() => { labICCID.Text = "ICCID: " + strRsp[(idx + 1)..]; }));
            }
            if (strRsp.Contains("IMEI") && idx > 0)
            {
                BeginInvoke(new Action(() => { labIMEI.Text = "IMEI: " + strRsp[(idx + 1)..]; }));
            }
            if (strRsp.Contains("STA") && idx > 0)
            {
                var l = strRsp.IndexOf('(') + 1;
                var r = strRsp.IndexOf(')');
                strRsp = strRsp[l..r];
                var segs = strRsp.Split(',');
                var strSTA = segs[0];//.Remove('(');
                var strCSQ = segs[1];//.Remove(')');
                if (uint.TryParse(strSTA, out uint sta) &&
                    uint.TryParse(strCSQ, out uint csq))
                {
                    BeginInvoke(new Action(() => { statusLabel4.Text = $"{GetLTEState2Str(sta)} {GetCSQLevelStr(csq)}"; }));
                }                
            }
        }
    }
}

/* 
 * CSQ（Carrier to Signal Quality），即载波信号质量，是一种衡量无线信号质量的指标。以dB（分贝）为单位，数值越高表示无线信号质量越高。
 * 信号质量的划分:
    00~09 （-113-95dBm）信号差
    10~14 （-93-85dBm） 信号一般
    15~19 （-83-75dBm） 信号好
    20~30 （-73-53dBm） 信号很好

DEV_STA_OK              = 0 # 正常
DEV_STA_NO_SIMCARD      = 1 # 无SIM卡
DEV_STA_NO_NETWORK      = 2 # 无网络
DEV_STA_GNSS_NOT_FIXED  = 3 # GNSS未定位
DEV_STA_SRV_CONN_FAIL   = 4 # 服务器连接失败
DEV_STA_SRV_AUTH_FAIL   = 5 # 未授权
DEV_STA_RTCM_OUTTIME    = 6 # RTCM数据超时
DEV_STA_REBOOTING       = 7 # 设备重启中
*/
